[[...path]].page.tsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import React from 'react';
  2. import { IUserHasId, IUser } from '@growi/core';
  3. import { NextPage, GetServerSideProps, GetServerSidePropsContext } from 'next';
  4. import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
  5. import dynamic from 'next/dynamic';
  6. import { useRouter } from 'next/router';
  7. import { NoLoginLayout } from '~/components/Layout/NoLoginLayout';
  8. import { InvitedFormProps } from '~/components/Login/InvitedForm';
  9. import { CrowiRequest } from '~/interfaces/crowi-request';
  10. import { useCsrfToken, useCurrentPathname, useCurrentUser } from '../../stores/context';
  11. import {
  12. CommonProps, getServerSideCommonProps, useCustomTitle, getNextI18NextConfig,
  13. } from '../utils/commons';
  14. const LoginForm = dynamic(() => import('~/components/Login/LoginForm'), { ssr: false });
  15. const InvitedForm = dynamic<InvitedFormProps>(() => import('~/components/Login/InvitedForm').then(mod => mod.InvitedForm), { ssr: false });
  16. type Props = CommonProps & {
  17. isMailerSetup: boolean,
  18. enabledStrategies: unknown,
  19. registrationWhiteList: string[],
  20. currentUser: IUser,
  21. invitedFormUsername: string,
  22. invitedFormName: string,
  23. }
  24. const LoginPage: NextPage<Props> = (props: Props) => {
  25. const router = useRouter();
  26. const { path } = router.query;
  27. const pagePathKeys: string[] = Array.isArray(path) ? path : ['login'];
  28. useCsrfToken(props.csrfToken);
  29. useCurrentPathname(props.currentPathname);
  30. useCurrentUser(props.currentUser);
  31. const loginPagesMap = {
  32. login: {
  33. component: <LoginForm
  34. isLocalStrategySetup={true}
  35. isLdapStrategySetup={true}
  36. objOfIsExternalAuthEnableds={props.enabledStrategies}
  37. isRegistrationEnabled={true}
  38. isPasswordResetEnabled={true}
  39. registrationWhiteList={props.registrationWhiteList}
  40. />,
  41. classNames: ['login-page'],
  42. },
  43. invited: {
  44. component: <InvitedForm
  45. invitedFormUsername={props.invitedFormUsername}
  46. invitedFormName={props.invitedFormName}
  47. />,
  48. classNames: ['invited-page'],
  49. },
  50. };
  51. const getTargetPageToRender = (pagesMap, keys): {component: JSX.Element, classNames: string[]} => {
  52. return keys.reduce((pagesMap, key) => {
  53. return pagesMap[key];
  54. }, pagesMap);
  55. };
  56. const targetPage = getTargetPageToRender(loginPagesMap, pagePathKeys);
  57. return (
  58. <NoLoginLayout title={useCustomTitle(props, 'GROWI')} className={targetPage.classNames.join(' ')}>
  59. { targetPage.component }
  60. </NoLoginLayout>
  61. );
  62. };
  63. async function injectServerConfigurations(context: GetServerSidePropsContext, props: Props): Promise<void> {
  64. const req: CrowiRequest = context.req as CrowiRequest;
  65. const { crowi, body: invitedForm } = req;
  66. const { mailService, configManager } = crowi;
  67. props.isMailerSetup = mailService.isMailerSetup;
  68. props.registrationWhiteList = configManager.getConfig('crowi', 'security:registrationWhiteList');
  69. if (props.invitedFormUsername != null) {
  70. props.invitedFormUsername = invitedForm.username;
  71. }
  72. if (props.invitedFormName != null) {
  73. props.invitedFormName = invitedForm.name;
  74. }
  75. }
  76. function injectEnabledStrategies(context: GetServerSidePropsContext, props: Props): void {
  77. const req: CrowiRequest = context.req as CrowiRequest;
  78. const { crowi } = req;
  79. const { configManager } = crowi;
  80. const enabledStrategies = {
  81. google: configManager.getConfig('crowi', 'security:passport-google:isEnabled'),
  82. github: configManager.getConfig('crowi', 'security:passport-github:isEnabled'),
  83. facebook: false,
  84. twitter: configManager.getConfig('crowi', 'security:passport-twitter:isEnabled'),
  85. smal: configManager.getConfig('crowi', 'security:passport-saml:isEnabled'),
  86. oidc: configManager.getConfig('crowi', 'security:passport-oidc:isEnabled'),
  87. basic: configManager.getConfig('crowi', 'security:passport-basic:isEnabled'),
  88. };
  89. props.enabledStrategies = enabledStrategies;
  90. }
  91. /**
  92. * for Server Side Translations
  93. * @param context
  94. * @param props
  95. * @param namespacesRequired
  96. */
  97. async function injectNextI18NextConfigurations(context: GetServerSidePropsContext, props: Props, namespacesRequired?: string[] | undefined): Promise<void> {
  98. const nextI18NextConfig = await getNextI18NextConfig(serverSideTranslations, context, namespacesRequired);
  99. props._nextI18Next = nextI18NextConfig._nextI18Next;
  100. }
  101. export const getServerSideProps: GetServerSideProps = async(context: GetServerSidePropsContext) => {
  102. const req = context.req as CrowiRequest<IUserHasId & any>;
  103. const { user } = req;
  104. const result = await getServerSideCommonProps(context);
  105. // check for presence
  106. // see: https://github.com/vercel/next.js/issues/19271#issuecomment-730006862
  107. if (!('props' in result)) {
  108. throw new Error('invalid getSSP result');
  109. }
  110. const props: Props = result.props as Props;
  111. if (user != null) {
  112. props.currentUser = user.toObject();
  113. }
  114. await injectServerConfigurations(context, props);
  115. injectEnabledStrategies(context, props);
  116. await injectNextI18NextConfigurations(context, props, ['translation']);
  117. return { props };
  118. };
  119. export default LoginPage;